<?php

namespace hiduoke\services\upload\driver;

use hiduoke\base\BaseUpload;
use hiduoke\exception\UploadException;
use Qcloud\Cos\Client;
use think\exception\ValidateException;
use QCloud\COSSTS\Sts;
use think\File;

/**
 * 腾讯云COS文件上传
 * @package hiduoke\services\upload\driver
 * User: liuhongbin
 * Date: 2021-10-01 22:18
 */
class Cos extends BaseUpload
{
    /**
     * secretId
     * @var mixed
     */
    protected $secretId;

    /**
     * secretKey
     * @var mixed
     */
    protected $secretKey;

    /**
     * 句柄
     * @var Client
     */
    protected $handle;

    /**
     * 空间域名 Domain
     * @var mixed
     */
    protected $storageDomain;

    /**
     * 存储空间名称  公开空间
     * @var mixed
     */
    protected $storageName;

    /**
     * COS使用  所属地域
     * @var mixed|null
     */
    protected $storageRegion;

    /**
     * 初始化
     * @param array $config
     * @return mixed|void
     */
    public function initialize(array $config)
    {
        parent::initialize($config);
        $this->secretId = $config['cos_secret_id'] ?? null;
        $this->secretKey = $config['cos_secret_key'] ?? null;
        $this->storageName = $config['cos_storage_name'] ?? null;
        $this->storageRegion = $config['cos_storage_region'] ?? null;
        $this->storageDomain = $config['cos_domain'] ?? null;
    }

    /**
     * 实例化cos
     * @return mixed|Client
     * @throws UploadException
     */
    protected function app()
    {
        if (!$this->secretId || !$this->secretKey) {
            throw new UploadException('secretId 和 secretKey 不能为空');
        }
        $this->handle = new Client([
            'region'      => $this->storageRegion,
            'credentials' =>
                [
                    'secretId'  => $this->secretId,
                    'secretKey' => $this->secretKey
                ]
        ]);
        return $this->handle;
    }

    /**
     * 上传文件
     * @param string|file\UploadedFile|null $file 附件名
     * @param string|null $Stream 流内容
     * @param bool $isStream 是否为流上传
     * @return array|bool|\StdClass
     */
    protected function upload( $file = null, string $Stream = null, bool $isStream = false)
    {
        if (!$isStream) {
            if(is_string($file)){
                $fileHandle = app()->request->file($file);
            }else{
                $fileHandle = $file;
                $file = $file->getFilename();
            }
            if (!$fileHandle) {
                throw new UploadException("上传配置有误");
            }
            $this->validateCheck($file, $fileHandle);
            $key = $this->createFileName($fileHandle->getRealPath(), $fileHandle->getOriginalExtension());
            $body = fopen($fileHandle->getRealPath(), 'rb');
        } else {
            $key = $file;
            $body = $Stream;
        }
        try {
            $filePath = $this->path . '/' . $key;
            $this->fileInfo->uploadInfo = $this->app()->putObject([
                'Bucket' => $this->storageName,
                'Key'    => $filePath,
                'Body'   => $body
            ]);
            $this->fileInfo->filePath = $filePath;
            $this->fileInfo->fileUrl = $this->storageDomain . '/' . $filePath;
            $this->fileInfo->oldName = isset($fileHandle) ? $fileHandle->getOriginalName() : $key;
            $this->fileInfo->fileName = $key;
            return $this->fileInfo;
        } catch (\Exception $e) {
            throw new UploadException($e->getMessage());
        }
    }


    /**
     * 文件流上传
     * @param string $Stream
     * @param string|null $key
     * @return array|bool|mixed|\StdClass
     */
    public function stream(string $Stream, string $key = null)
    {
        if (!$key) {
            $key = $this->createFileName();
        }
        return $this->upload($key, $Stream, true);
    }

    /**
     * 文件上传
     * @param string $file
     * @return array|bool|mixed|\StdClass
     */
    public function save( $file = 'file')
    {
        return $this->upload($file);
    }

    /**
     * 删除资源
     * @param $key
     * @return mixed
     */
    public function delete(string $filePath)
    {
        try {
            return $this->app()->deleteObject(['Bucket' => $this->storageName, 'Key' => $filePath]);
        } catch (\Exception $e) {
            return $e->getMessage();
        }
    }
}
